#ifndef _TASKQUEUE_H
#define _TASKQUEUE_H

#include "10_Mutex.hpp"
#include "11_ConditionVariable.hpp"

#include <queue>
#include <stdio.h>

#define log() \
    printf("%s | %d | %s :debug \n", __FILE__, __LINE__, __FUNCTION__);
using std::queue;

// #define Elemtype Task // 函数不实现多态时不适用
// class Task;

// 此处可以定义Task，语法没错，通用考虑可以定义为模板
//#include <functional>
//using Task = std::function<void()>;

template <typename T>
class TaskQueue
{
public:
    TaskQueue(int queue_max_size);
    ~TaskQueue() = default;
    bool empty();
    bool full();
    void push(const T& data);
    T pop();
    void wakeup();

private:
    queue<T> _queue;
    int _queue_max_size;
    Mutex _mutex;
    ConditionVariable _notfull;
    ConditionVariable _notempty;
    bool _is_exit;

};

// 这部分反而需要放在hpp方便编译器查找，放在cpp里会直接报错
template<typename T>
TaskQueue<T>::TaskQueue(int queue_max_size)
    :_queue(queue<T>())
    ,_queue_max_size(queue_max_size)
    ,_mutex()
    ,_notfull()
    ,_notempty()
    ,_is_exit(false)
{}

template<typename T>
bool TaskQueue<T>::empty()
{
    return _queue.size() == 0;
}

template<typename T>
bool TaskQueue<T>::full()
{
    return static_cast<int>(_queue.size()) == _queue_max_size;
}

template<typename T>
void TaskQueue<T>::push(const T& data)
{
    Mutex::LockGuard lock(_mutex);

    while(full())
    {
        _notfull.wait(_mutex);
    }

    _queue.push(data);
    
    _notempty.notify_one();

}

template<typename T>
T TaskQueue<T>::pop()
{
    Mutex::LockGuard lock(_mutex);

    while(empty() && _is_exit == false)
    {
        _notempty.wait(_mutex);
    }

    if(_is_exit == false)
    {
        T data = _queue.front();
        _queue.pop();

        _notfull.notify_one();
        return data;
    }
    else
    {
        log();
        return nullptr;
    }

}

template<typename T>
void TaskQueue<T>::wakeup()
{
    _is_exit = true;
    _notempty.notify_all();
    //_notfull.notify_all();  // 不管了，我生气了，都醒醒，一个也别想睡
    log();
}

#endif

